package toman.orm;

import toman.QueryEngine;
import toman.QueryForUpdate;
import toman.TOMan;
import toman.TOQuery;

/**
 * The base for query language query engines like SQL, JPQL or HQL query engines.
 * <br>
 * User: zslajchrt
 * Date: 2.5.11
 * Time: 18:20
 */
public abstract class TOAnnotQueryEngine implements QueryEngine {

    private TO getTOAnnotation(Class<?> toClass) {
        return getTOAnnotation_(toClass, toClass);
    }

    private TO getTOAnnotation_(Class<?> toClass, Class<?> origClass) {
        if (toClass == Object.class) {
            throw new IllegalArgumentException("Class" + origClass.getName() + " is not annotated with @TO");
        }

        TO to = toClass.getAnnotation(TO.class);
        if (to == null) {
            return getTOAnnotation_(toClass.getSuperclass(), origClass);
        }
        return to;
    }

    public <T, K> boolean canFindInitObject(TOMan toman, Class<T> toClass, K toId) {
        return getTOAnnotation(toClass) != null;
    }

    public <T> boolean canCreateQueryForUpdate(TOMan toman, T to) {
        return getTOAnnotation(to.getClass()) != null;
    }

    public <T> boolean canCreateQuery(TOMan toman, Class<T> toClass, Object queryDefinition) {
        return getTOAnnotation(toClass) != null && (queryDefinition == null || queryDefinition instanceof String);
    }

    public <T, K> Object findInitObject(TOMan toman, Class<T> toClass, K toId) throws Exception {
        TO toAnnot = getTOAnnotation(toClass);
        return findInitObject(toman, toClass, toId, toAnnot.read(), toAnnot.id());
    }

    protected abstract <T, K> Object findInitObject(TOMan toman, Class<T> toClass, K toId, String readQueryDef, String idClauseDef) throws Exception;

    public <T> QueryForUpdate createQueryForUpdate(TOMan toman, T to) throws Exception {
        TO toAnnot = getTOAnnotation(to.getClass());
        return createQueryForUpdate(toman, to, toman.resolvePossibleExpression(toAnnot.write(), to), toAnnot.id());
    }

    protected abstract <T> QueryForUpdate createQueryForUpdate(TOMan toman, T to, Object updateQueryDef, String idClauseDef) throws Exception;

    public <T> TOQuery<T> createQuery(TOMan toman, Class<T> toClass, Object conditionDef) throws Exception {
        TO toAnnot = getTOAnnotation(toClass);
        return createQuery(toman, toClass, toAnnot.read(), conditionDef);
    }

    protected abstract <T> TOQuery<T> createQuery(TOMan toman, Class<T> toClass, String readQueryDef, Object conditionDef) throws Exception;

    public Object getPropertyValue(Object contextObject, String propertyName) {
        return null;
    }
}
